package com.youlu.campus.service.activity.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.mongodb.client.result.DeleteResult;
import com.youlu.campus.activity.service.UserActivityTaskRankingService;
import com.youlu.campus.base.exception.BusinessException;
import com.youlu.campus.base.exception.NameAndUniversityException;
import com.youlu.campus.base.interactive.vo.ActivitySignUpRequest;

import com.youlu.campus.entity.ActivityFeedInfo;
import com.youlu.campus.entity.ActivityInfo;
import com.youlu.campus.entity.ActivityPlatformConfig;
import com.youlu.campus.entity.ActivityQaInfo;
import com.youlu.campus.entity.ActivityTaskInfo;
import com.youlu.campus.entity.UniversityInfo;
import com.youlu.campus.entity.UserActivityPointDetail;
import com.youlu.campus.service.ranking.entity.UserActivityPointRanking;
import com.youlu.campus.entity.UserActivityTaskInfo;
import com.youlu.campus.entity.UserInfoExtend;
import com.youlu.campus.entity.UserInviteCount;
import com.youlu.campus.entity.UserInviteRecord;
import com.youlu.campus.entity.UserPO;
import com.youlu.campus.entity.UserParticipateActivityInfo;
import com.youlu.campus.entity.UserPointsDetail;
import com.youlu.campus.entity.UserQaInfo;
import com.youlu.campus.entity.UserQaRanking;
import com.youlu.campus.entity.VO.res.UserJoinActivityRes;
import com.youlu.campus.entity.VO.res.UserParticipateActivityRes;
import com.youlu.campus.entity.VO.res.UserQaRes;
import com.youlu.campus.entity.ca.UserCa;
import com.youlu.campus.entity.commission.DistributorChannelActivity;
import com.youlu.campus.entity.data.UniversityStatistics;
import com.youlu.campus.entity.english.UserCompetitionQaAnswer;
import com.youlu.campus.entity.english.UserQuestionInfo;
import com.youlu.campus.entity.enums.TaskBizType;
import com.youlu.campus.entity.jinshuju.JinUserParticipate;
import com.youlu.campus.service.activity.ActivityService;
import com.youlu.campus.service.activity.ActivityTaskService;
import com.youlu.campus.service.activity.UserParticipateActivityInfoService;
import com.youlu.campus.service.ca.UserCaService;
import com.youlu.campus.service.commission.DistributorChannelActivityService;
import com.youlu.campus.service.course.UserActivityService;
import com.youlu.campus.service.data.UniversityStatisticsService;
import com.youlu.campus.service.feed.ActivityFeedInfoService;
import com.youlu.campus.service.invite.UserInviteService;
import com.youlu.campus.service.platform.PointPlatformConfigService;
import com.youlu.campus.service.qa.ActivityQaInfoService;
import com.youlu.campus.service.qa.UserQaInfoService;
import com.youlu.campus.service.qa.impl.UserQaRankingService;
import com.youlu.campus.service.ranking.UserPointRankingService;
import com.youlu.campus.service.university.UniversityInfoService;
import com.youlu.campus.service.visitor.UserInfoExtendService;
import com.youlu.campus.service.visitor.UserPointsService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.FindAndModifyOptions;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

@Slf4j
@Service
public class UserParticipateActivityInfoServiceImpl implements UserParticipateActivityInfoService {
    @Autowired
    private MongoTemplate mongoTemplate;

    @Lazy
    @Autowired
    private ActivityService activityService;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private UniversityStatisticsService universityStatisticsService;
    @Autowired
    private UniversityInfoService universityInfoService;
    @Autowired
    private ActivityTaskService activityTaskService;

    @Autowired
    private UserCaService userCaService;

    @Autowired
    private UserQaRankingService userQaRankingService;

    @Autowired
    private UserInfoExtendService userInfoExtendService;
    @Autowired
    private PointPlatformConfigService pointPlatformConfigService;
    @Autowired
    private UserPointsService userPointsService;

    @Autowired
    private UserPointRankingService userPointRankingService;
    @Autowired
    private ActivityFeedInfoService activityFeedInfoService;


    @Autowired
    private UserActivityService userActivityService;

    @Lazy
    @Autowired
    private UserQaInfoService userQaInfoService;
    @Lazy
    @Autowired
    private UserInviteService userInviteService;
    @Autowired
    private ActivityQaInfoService activityQaInfoService;

    @Lazy
    @Autowired
    private DistributorChannelActivityService distributorChannelActivityService;

    @Resource(name = "masterMongoTemplate")
    private MongoTemplate masterMongoTemplate;

    @Autowired
    private UserActivityTaskRankingService userActivityTaskRankingService;

    public static final String ACTIVITY_COUNT_USERS_PEFIX = "youlu:runtime:activity-users:count:activityId:%s";

    @Override
    public UserQaRes findUserQaByUserIdAndActivityId(String userId, String activityId, String activityQaInfoId) {
        UserQaRes userQaRes = new UserQaRes();
        ActivityInfo activityInfo = activityService.findOne(activityId);
        userQaRes.setSignUpTips(activityInfo.getSignUpTips());
        userQaRes.setQaPassTips(activityInfo.getQaPassTips());
        userQaRes.setQaNotPassTips(activityInfo.getQaNotPassTips());
        userQaRes.setInviteTips(activityInfo.getInviteTips());
        Query query = new Query();
        //是否多级答题
        if (!activityInfo.getHasMultiQa()) {
            query.addCriteria(Criteria.where("userId").is(userId).and("activityId").is(activityId));
            query.addCriteria(Criteria.where("joined").is(Boolean.TRUE));
            UserParticipateActivityInfo userParticipateActivityInfo = this.mongoTemplate.findOne(query,
                    UserParticipateActivityInfo.class);
            if (Objects.isNull(userParticipateActivityInfo)) {
                return null;
            }
            userQaRes.setPassed(userParticipateActivityInfo.getPassed());
            userQaRes.setQaScore(userParticipateActivityInfo.getCurrentQaScore());
            return userQaRes;
        }
        //可能存在主从延迟问题
        query = new Query();
        query.addCriteria(Criteria.where("userId").is(userId).and("activityId").is(activityId));
        query.addCriteria(Criteria.where("activityQaInfoId").is(activityQaInfoId));
        UserQaInfo userQaInfo = this.mongoTemplate.findOne(query, UserQaInfo.class);
        if (Objects.isNull(userQaInfo)) {
            log.error(":>>> 第1次查询:未获取到答题信息,userId:{},activityId:{},activityQaInfoId:{}", userId, activityId,
                    activityQaInfoId);
            userQaInfo = this.mongoTemplate.findOne(query, UserQaInfo.class);
            if (Objects.isNull(userQaInfo)) {
                log.error(":>>> 第2次查询:未获取到答题信息,userId:{},activityId:{},activityQaInfoId:{}", userId, activityId,
                        activityQaInfoId);
                throw new BusinessException("未获取到答题信息");
            }
        }
        userQaRes.setPassed(userQaInfo.getPassed());
        userQaRes.setQaScore(userQaInfo.getQaScore());
        return userQaRes;
    }

    @Override
    public UserParticipateActivityInfo findBy(String activityId, String userId) {
        Query query = new Query();
        query.addCriteria(Criteria.where("userId").is(userId).and("activityId").is(activityId));
        List<UserParticipateActivityInfo> ups = mongoTemplate.find(query, UserParticipateActivityInfo.class);
        log.info(":>>> 用户:{} 参与活动:{} 报名记录有:{} 条", userId, activityId, ups == null ? 0 : ups.size());
        if (CollectionUtils.isEmpty(ups)) {
            log.error(":>>> 用户:{} 没有报名:{} 活动", userId, activityId);
            return null;
        }
        for (UserParticipateActivityInfo up : ups) {
            if (Boolean.TRUE.equals(up.getJoined())) {
                return up;
            }
        }
        return ups.get(0);
    }

    @Override
    public UserParticipateActivityInfo findBy(String activityId, String userId, List<String> uids) {
        log.info(":>>> 开始获取用户:{} 活动:{} 报名信息:{}", userId, activityId);
        Long start = System.currentTimeMillis();
        Query query = new Query();
        if (!uids.contains(userId)) {
            uids.add(userId);
        }
        query.addCriteria(Criteria.where("userId").in(uids).and("activityId").is(activityId));
        log.info(":>>> 用户:{} 存在相关联的账户:{}", userId, JSON.toJSON(uids));
        List<UserParticipateActivityInfo> ups = mongoTemplate.find(query, UserParticipateActivityInfo.class);
        log.info(":>>> 用户:{} 参与活动:{} 报名记录有:{} 条", userId, activityId, ups == null ? 0 : ups.size());
        if (Objects.isNull(ups) || CollectionUtils.isEmpty(ups)) {
            log.error(":>>> 用户:{} 没有报名:{} 活动,耗时:{} 毫秒", userId, activityId, System.currentTimeMillis() - start);
            return null;
        }
        for (UserParticipateActivityInfo up : ups) {
            if (Boolean.TRUE.equals(up.getJoined())) {
                log.info(":>>> 活动:{},用户:{} 关联账号:{} 已经报名,耗时:{} 毫秒", activityId, userId, JSON.toJSONString(uids),
                        System.currentTimeMillis() - start);
                return up;
            }
        }
        log.info(":>>> 活动:{},用户:{} 关联账号:{} 未报名,耗时:{} 毫秒", activityId, userId, JSON.toJSONString(uids),
                System.currentTimeMillis() - start);
        return ups.get(0);
    }

    @Override
    public UserParticipateActivityInfo findByMobile(String activityId, String mobile, Boolean joinStatus) {
        log.info(":>>> 开始查找手机号:{},活动是否有报名信息:{},报名状态:{} ", mobile, activityId, joinStatus);
        Query query = new Query().addCriteria(Criteria.where("mobile").is(mobile)
                .and("activityId").is(activityId)
                .and("joined").is(joinStatus));
        UserParticipateActivityInfo exist = mongoTemplate.findOne(query, UserParticipateActivityInfo.class);
        return exist;
    }

    @Override
    public void exportUserParticipate() {
        Integer pageNo = 1;
        Integer pageSize = 10000;
        Long sheetMaxCount = 1000000L;
        String fileName = "/home/excel/活动用户报名表.xlsx";
        AtomicLong count = new AtomicLong(0);
        AtomicInteger sheetMax = new AtomicInteger(0);
        ExcelWriter excelWriter = EasyExcel.write(fileName, UserParticipateActivityRes.class).build();
        while (true) {
            log.info("开始 第 {} 页,总数据大小-> {},第 {} 个 sheet", pageNo, count.get(), sheetMax.get());
            PageRequest pageRequest = PageRequest.of(pageNo - 1, pageSize);
            Query query = new Query();
            query.addCriteria(Criteria.where("joined").is(Boolean.TRUE));
            List<UserParticipateActivityInfo> list = this.mongoTemplate.find(query.with(pageRequest),
                    UserParticipateActivityInfo.class);
            if (org.apache.commons.collections4.CollectionUtils.isEmpty(list)) {
                break;
            }
            List<UserParticipateActivityRes> exportList = list.stream().map(userParticipateActivityInfo -> {
                UserParticipateActivityRes userParticipateActivityRes = new UserParticipateActivityRes();
                userParticipateActivityRes.setName(userParticipateActivityInfo.getName());
                userParticipateActivityRes.setMobile(userParticipateActivityInfo.getMobile());
                userParticipateActivityRes.setGrade(userParticipateActivityInfo.getGrade());
                if (StringUtils.isNotBlank(userParticipateActivityInfo.getUniversityId()) && StringUtils.isNotBlank(userParticipateActivityInfo.getUniversityName())) {
                    userParticipateActivityRes.setUniversityName(userParticipateActivityInfo.getUniversityName());
                    UniversityInfo universityInfo =
                            this.mongoTemplate.findById(userParticipateActivityInfo.getUniversityId(),
                                    UniversityInfo.class);
                    if (Objects.nonNull(universityInfo)) {
                        userParticipateActivityRes.setProvice(universityInfo.getProvince());
                        userParticipateActivityRes.setCity(universityInfo.getCity());
                    }
                } else {
                    userParticipateActivityRes.setUniversityName(userParticipateActivityInfo.getUniversityName());
                }
                return userParticipateActivityRes;
            }).collect(Collectors.toList());
            long x = count.addAndGet(exportList.size());
            log.info("开始 第 {} 页，总数据大小->{}", pageNo, x);
            if (x <= sheetMaxCount) {
                WriteSheet writeSheet = EasyExcel.writerSheet(sheetMax.get(), "报名表" + sheetMax.get()).build();
                excelWriter.write(exportList, writeSheet);
            } else {
                log.error("当前页->{},超过总数据大小->{}", pageNo, x);
                sheetMax.addAndGet(1);
                //重置
                count.set(0L);
                count.addAndGet(exportList.size());
                WriteSheet writeSheet = EasyExcel.writerSheet(sheetMax.get(), "报名表" + sheetMax.get()).build();
                excelWriter.write(exportList, writeSheet);
            }
            log.info("总数据大小-> {},第 {} 个 sheet", pageNo, count.get(), sheetMax.get());
            pageNo++;
        }
        excelWriter.finish();

    }

    @Override
    public Long getJoinedCount(String activityId) {
        String key = getJoinedCountKey(activityId);
        Long count = redisTemplate.opsForValue().increment(key, 0L);
        log.info(":>>> 从缓存中获取参与人员数量:{},key:{},count:{}", activityId, key, count);
        return count;
    }

    @Async
    @Override
    public void increJoinedCount(String activityId, Long incr) {
        log.info(":>>> 开始累加活动报名人数:{},{}", activityId, incr);
        try {
            String key = getJoinedCountKey(activityId);
            Long r = redisTemplate.opsForValue().increment(key, incr);
            log.info(":>>> 累加活动:{}--:{}  报名人数结果:{}", activityId, incr, r);
            redisTemplate.expire(key, 3650, TimeUnit.DAYS);
        } catch (Exception e) {
            log.error(":>>> 开始累加报名,错误:{}", e);
            return;
        }

    }

    @Override
    public void statisticsActivity(Long total) {
        Integer pageSize = 10000;
        Integer pages = total.intValue() / pageSize + 1;
        Query query = new Query().addCriteria(Criteria.where("joined").is(Boolean.TRUE));
        for (int i = 0; i < pages + 1; i++) {
            log.info(":>>> 开始处理第:{} 页 ", i);
            query.skip((i - 1) * pageSize);
            query.limit(pageSize);
            List<UserParticipateActivityInfo> datas = mongoTemplate.find(query, UserParticipateActivityInfo.class);
            if (CollectionUtils.isEmpty(datas)) {
                log.info(":>>> 第:{} 页数据为空 ", i);
                continue;
            }
            for (UserParticipateActivityInfo up : datas) {
                if (StringUtils.isBlank(up.getActivityId()) || StringUtils.isBlank(up.getMobile()) || StringUtils.isBlank(up.getUniversityId())) {
                    continue;
                }
                Query query1 =
                        new Query().addCriteria(Criteria.where("mobile").is(up.getMobile()).and("activityId").ne(up.getActivityId()).and("joined").is(Boolean.TRUE));
                Long t = mongoTemplate.count(query1, UserParticipateActivityInfo.class);
                Long key = t + 1L;
                UniversityStatistics universityStatistics =
                        universityStatisticsService.findByUniversityId(up.getUniversityId());
                if (Objects.isNull(universityStatistics)) {
                    universityStatistics = new UniversityStatistics();
                    universityStatistics.setUniversityId(up.getUniversityId());
                    universityStatistics.setSignUpNum(1L);
                    universityStatistics.getSignUpDatas().put(key.intValue(), 1L);
                    UniversityInfo universityInfo = universityInfoService.findOne(up.getUniversityId());
                    if (Objects.nonNull(universityInfo)) {
                        universityStatistics.setUniversityName(universityInfo.getName());
                    }
                    universityStatisticsService.create(universityStatistics);
                    log.info(":>>> 大学:{} 统计不存在,新增:{}", up.getUniversityId(), JSON.toJSON(universityStatistics));
                    continue;
                }
                universityStatistics.setSignUpNum(1L);
                if (universityStatistics.getSignUpDatas().containsKey(key.intValue())) {
                    universityStatistics.getSignUpDatas().put(key.intValue(),
                            universityStatistics.getSignUpDatas().get(key.intValue()) + 1L);
                } else {
                    universityStatistics.getSignUpDatas().put(key.intValue(), 1L);
                }
                log.info(":>>> 大学:{} 统计存在,修改:{}", up.getUniversityId(), JSON.toJSON(universityStatistics));
                universityStatisticsService.update(universityStatistics);
            }
        }
    }

    @Async
    @Override
    public void saveOrUpdate(UserParticipateActivityInfo userParticipateActivityInfo) {
        log.info("【参与活动】用户 - > {} 参与活动 - > {}", userParticipateActivityInfo.getUserId(),
                userParticipateActivityInfo.getActivityId());
        Date now = new Date();
        Update update = new Update();
        Query query = new Query();
        query.addCriteria(Criteria.where("userId").is(userParticipateActivityInfo.getUserId()));
        if (StringUtils.isNotBlank(userParticipateActivityInfo.getActivityId())) {
            query.addCriteria(Criteria.where("activityId").is(userParticipateActivityInfo.getActivityId()));
        } else {
            query.addCriteria(Criteria.where("activityId").exists(Boolean.TRUE));
        }
        if (StringUtils.isNotBlank(userParticipateActivityInfo.getAppId())) {
            query.addCriteria(Criteria.where("appId").is(userParticipateActivityInfo.getAppId()));
        }
        boolean exists = this.mongoTemplate.exists(query, UserParticipateActivityInfo.class);
        if (!exists) {
            update.set("createdTime", now);
        }
        if (userParticipateActivityInfo.getJoined()) {
            update.setOnInsert("signUpTime", now);
        }
        update.set("updatedTime", now);
        update.inc("updateNameCount", 0);
        if (StringUtils.isNotBlank(userParticipateActivityInfo.getUniversityId())) {
            update.set("universityId", userParticipateActivityInfo.getUniversityId());
        }
        if (StringUtils.isNotBlank(userParticipateActivityInfo.getUniversityName())) {
            update.set("universityName", userParticipateActivityInfo.getUniversityName());
        }
        if (StringUtils.isNotBlank(userParticipateActivityInfo.getGrade())) {
            update.set("grade", userParticipateActivityInfo.getGrade());
        }
        if (StringUtils.isNotBlank(userParticipateActivityInfo.getName())) {
            update.set("name", userParticipateActivityInfo.getName());
        }
        if (StringUtils.isNotBlank(userParticipateActivityInfo.getNickName())) {
            update.set("nickName", userParticipateActivityInfo.getNickName());
        }
        if (StringUtils.isNotBlank(userParticipateActivityInfo.getMobile())) {
            update.set("mobile", userParticipateActivityInfo.getMobile());
        }
        if (StringUtils.isNotBlank(userParticipateActivityInfo.getCaName())) {
            update.set("caName", userParticipateActivityInfo.getCaName());
        }
        if (StringUtils.isNotBlank(userParticipateActivityInfo.getContestCaName())) {
            update.set("contestCaName", userParticipateActivityInfo.getContestCaName());
        }
        if (Objects.nonNull(userParticipateActivityInfo.getQaScore()) && userParticipateActivityInfo.getQaScore() > 0) {
            update.set("qaScore", userParticipateActivityInfo.getQaScore());
            update.set("currentQaScore", userParticipateActivityInfo.getQaScore());
        }
        if (Objects.nonNull(userParticipateActivityInfo.getProvinceQaScore()) && userParticipateActivityInfo.getProvinceQaScore() > 0) {
            update.set("provinceQaScore", userParticipateActivityInfo.getProvinceQaScore());
            update.set("currentQaScore", userParticipateActivityInfo.getProvinceQaScore());
        }
        if (Objects.nonNull(userParticipateActivityInfo.getCountryQaScore()) && userParticipateActivityInfo.getCountryQaScore().intValue() > 0) {
            update.set("countryQaScore", userParticipateActivityInfo.getCountryQaScore());
            update.set("currentQaScore", userParticipateActivityInfo.getCountryQaScore());
        }
        if (Objects.nonNull(userParticipateActivityInfo.getPassQaScore()) && userParticipateActivityInfo.getPassQaScore() > 0) {
            update.set("passQaScore", userParticipateActivityInfo.getPassQaScore());
        }
        if (StringUtils.isNotBlank(userParticipateActivityInfo.getAppId())) {
            update.set("appId", userParticipateActivityInfo.getAppId());
        }
        if (StringUtils.isNotBlank(userParticipateActivityInfo.getPlatform())) {
            update.set("platform", userParticipateActivityInfo.getPlatform());
        }
        if (StringUtils.isNotBlank(userParticipateActivityInfo.getAvatarUrl())) {
            update.set("avatarUrl", userParticipateActivityInfo.getAvatarUrl());
        }
        if (StringUtils.isNotBlank(userParticipateActivityInfo.getOpenId())) {
            update.set("openId", userParticipateActivityInfo.getOpenId());
        }
        if (StringUtils.isNotBlank(userParticipateActivityInfo.getUnionId())) {
            update.set("unionId", userParticipateActivityInfo.getUnionId());
        }
        if (StringUtils.isNotBlank(userParticipateActivityInfo.getActivityChannelId())) {
            DistributorChannelActivity distributorChannelActivity = distributorChannelActivityService.findByChannelIdAndActivityId(userParticipateActivityInfo.getActivityChannelId(), userParticipateActivityInfo.getActivityId());
            if (Objects.nonNull(distributorChannelActivity)) {
                update.set("activityChannelId", userParticipateActivityInfo.getActivityChannelId());
            }
        }
        update.set("fromMyPoint", userParticipateActivityInfo.getFromMyPoint());
        update.set("passed", userParticipateActivityInfo.getPassed());
        update.set("joined", userParticipateActivityInfo.getJoined());
        update.set("totalQaNum", userParticipateActivityInfo.getTotalQaNum());
        update.set("reTryQaNum", userParticipateActivityInfo.getReTryQaNum());
        FindAndModifyOptions findAndModifyOptions = new FindAndModifyOptions();
        findAndModifyOptions.returnNew(Boolean.TRUE);
        findAndModifyOptions.upsert(Boolean.TRUE);
        UserParticipateActivityInfo userSignUp = this.mongoTemplate.findAndModify(query, update, findAndModifyOptions
                , UserParticipateActivityInfo.class);
        if (Objects.nonNull(userSignUp) && userParticipateActivityInfo.getSignUpVideo()) {
            userActivityService.addRegisterActivityNum(userParticipateActivityInfo.getActivityId(), 1);
            this.increJoinedCount(userParticipateActivityInfo.getActivityId(), 1L);
            activityService.updateActivityJoinNum(userParticipateActivityInfo.getActivityId(), 1, new Date());
        }


    }

    @Override
    public UserParticipateActivityInfo findByUserIdActivityId(String userId, String activityId) {
        Query query = new Query();
        query.addCriteria(Criteria.where("userId").is(userId).and("activityId").is(activityId));
        return mongoTemplate.findOne(query, UserParticipateActivityInfo.class);
    }

    @Override
    public UserJoinActivityRes findJoinActivityByUserId(String userId) {
        Query query = new Query().addCriteria(Criteria.where("platform").is("qq").and("status").is(true));
        List<ActivityPlatformConfig> apcList = mongoTemplate.find(query, ActivityPlatformConfig.class);
        if (CollectionUtils.isEmpty(apcList)) {
            return new UserJoinActivityRes();
        }
        List<String> activityIdList = apcList.stream().map(apc -> apc.getActivityId()).collect(Collectors.toList());
        query = new Query();
        query.addCriteria(Criteria.where("userId").is(userId));
        query.addCriteria(Criteria.where("activityId").in(activityIdList));
        query.addCriteria(Criteria.where("joined").is(Boolean.TRUE));
        List<UserParticipateActivityInfo> list = this.mongoTemplate.find(query, UserParticipateActivityInfo.class);
        if (CollectionUtils.isEmpty(list)) {
            return new UserJoinActivityRes();
        }
        UserJoinActivityRes userJoinActivityRes = new UserJoinActivityRes();
        if (list.size() > 1) {//参与了多个活动
            userJoinActivityRes.setJoinType(2);
            return userJoinActivityRes;
        }
        //一个活动
        UserParticipateActivityInfo userParticipateActivityInfo = list.get(0);
        userJoinActivityRes.setActivityId(userParticipateActivityInfo.getActivityId());
        userJoinActivityRes.setJoinType(1);
        ActivityTaskInfo activityTaskInfo = activityTaskService.find(userParticipateActivityInfo.getActivityId(),
                TaskBizType.INVITE);
        if (Objects.nonNull(activityTaskInfo)) {
            userJoinActivityRes.setTaskId(activityTaskInfo.getId());
        }
        return userJoinActivityRes;
    }

    @Override
    public void checkUserInfoSignUp(String userId, String activityId) {
        if (StringUtils.isBlank(userId) || StringUtils.isBlank(activityId)) {
            return;
        }
        UserParticipateActivityInfo userParticipateActivityInfo = this.findByUserIdActivityId(userId, activityId);
        if (Objects.isNull(userParticipateActivityInfo) || StringUtils.isBlank(userParticipateActivityInfo.getName()) || StringUtils.isBlank(userParticipateActivityInfo.getUniversityName())) {
            throw new NameAndUniversityException("请完善你的报名信息");
        }
    }

    @Override
    public void updateUserInfo(ActivitySignUpRequest activitySignUp) {
        if (StringUtils.isBlank(activitySignUp.getActivityId()) || StringUtils.isBlank(activitySignUp.getActivityId())) {
            return;
        }
        Query query = new Query();
        query.addCriteria(Criteria.where("userId").is(activitySignUp.getUserId()));
        query.addCriteria(Criteria.where("activityId").is(activitySignUp.getActivityId()));
        UserParticipateActivityInfo userParticipateActivityInfo = this.mongoTemplate.findOne(query,
                UserParticipateActivityInfo.class);
        if (Objects.isNull(userParticipateActivityInfo)) {
            throw new BusinessException("报名信息不存在");
        }
        Update update = new Update();
        if (StringUtils.isNotBlank(activitySignUp.getName())) {
            if (activitySignUp.getMustCode() && userParticipateActivityInfo.getUpdateNameCount() > 0) {
                throw new BusinessException("对不起，信息已不能修改,请联系我们");
            } else {
                if (activitySignUp.getMustCode()) {
                    update.inc("updateNameCount", 1);
                }
            }
            update.set("name", activitySignUp.getName());
        }
        if (StringUtils.isNotBlank(activitySignUp.getUniversityId()) && StringUtils.isNotBlank(activitySignUp.getUniversityName())) {
            update.set("universityId", activitySignUp.getUniversityId());
            update.set("universityName", activitySignUp.getUniversityName());
        }
        FindAndModifyOptions findAndModifyOptions = new FindAndModifyOptions();
        findAndModifyOptions.returnNew(Boolean.TRUE);
        findAndModifyOptions.upsert(Boolean.TRUE);
        UserParticipateActivityInfo modifyUserParticipateActivityInfo = this.mongoTemplate.findAndModify(query,
                update, findAndModifyOptions, UserParticipateActivityInfo.class);
        if (Objects.isNull(modifyUserParticipateActivityInfo)) {
            return;
        }
        //更新用户电子证书
        UserInfoExtend userInfoExtend = new UserInfoExtend();
        userInfoExtend.setUserId(activitySignUp.getUserId());
        userInfoExtend.setName(modifyUserParticipateActivityInfo.getName());
        userInfoExtend.setMobile(modifyUserParticipateActivityInfo.getMobile());
        userInfoExtend.setUniversityId(modifyUserParticipateActivityInfo.getUniversityId());
        userInfoExtend.setUniversityName(modifyUserParticipateActivityInfo.getUniversityName());
        userCaService.updateByUserId(userInfoExtend);

        //更新学校姓名信息
        UserQaRanking userQaRanking = new UserQaRanking();
        userQaRanking.setUniversityId(modifyUserParticipateActivityInfo.getUniversityId());
        userQaRanking.setUniversityName(modifyUserParticipateActivityInfo.getUniversityName());
        userQaRanking.setUserId(activitySignUp.getUserId());
        userQaRanking.setActivityId(activitySignUp.getActivityId());
        userQaRanking.setNickName(modifyUserParticipateActivityInfo.getNickName());
        userQaRankingService.updateByUserId(userQaRanking);


    }

    @Override
    public void signUpActivity(ActivitySignUpRequest request, UserPO userPO) {
        UserInfoExtend userInfoExtend = userInfoExtendService.findByUserIdAndAppId(userPO);
        if (Objects.isNull(userInfoExtend)) {
            userInfoExtend = new UserInfoExtend();
        }
        UserParticipateActivityInfo existUserParticipateActivityInfo = this.findByUserIdActivityId(userPO.getId(),
                request.getActivityId());
        if (Objects.nonNull(existUserParticipateActivityInfo)) {
            return;
        }
        // 添加Feed流
        ActivityFeedInfo feedInfo = new ActivityFeedInfo();
        feedInfo.setActivityId(request.getActivityId());
        feedInfo.setActivityStatus(2);
        feedInfo.setStatus(true);
        feedInfo.setImageUr(userPO.getAvatarUrl());
        feedInfo.setContent(userPO.getNickName() + "报名活动");
        activityFeedInfoService.addActivityFeedInfo(request.getActivityId(), 2, feedInfo);
        UserParticipateActivityInfo userParticipateActivityInfo = new UserParticipateActivityInfo();
        userParticipateActivityInfo.setJoined(Boolean.TRUE);
        userParticipateActivityInfo.setNickName(userPO.getNickName());
        userParticipateActivityInfo.setAvatarUrl(userPO.getAvatarUrl());
        userParticipateActivityInfo.setUniversityId(userInfoExtend.getUniversityId());
        userParticipateActivityInfo.setUniversityName(userInfoExtend.getUniversityName());
        userParticipateActivityInfo.setMobile(userInfoExtend.getMobile());
        userParticipateActivityInfo.setName(userInfoExtend.getName());
        userParticipateActivityInfo.setGrade(userInfoExtend.getGrade());
        userParticipateActivityInfo.setUserId(userPO.getId());
        userParticipateActivityInfo.setActivityId(request.getActivityId());
        userParticipateActivityInfo.setFromMyPoint(request.getFromMyPoint());
        this.saveOrUpdate(userParticipateActivityInfo);
        if (request.getFromMyPoint()) {
            log.info(":>>> 用户参加活动来源于我的积分页面,添加积分:{},{}", userPO.getId(), request.getActivityId());
            Integer point = pointPlatformConfigService.getPoint(request.getAppId(), "join-activity");
            UserPointsDetail detail = new UserPointsDetail();
            detail.setUserId(userPO.getId());
            detail.setAction("add");
            detail.setAppId(request.getAppId());
            detail.setPlatform(request.getPlatform());
            detail.setBizDesc("参加活动");
            detail.setBizType("join-activity");
            detail.setOptDate(new Date());
            detail.setPoints(point);
            detail.setComments("参加活动" + point + "积分");
            userPointsService.addPoint(detail);
            userPointRankingService.updatePoint(userPO, "", point);
        }
        request.setUserId(userPO.getId());
        request.setAppId(request.getAppId());
        request.setPlatform(userPO.getCurrentPlatform());
        activityService.extSignUpActivity(request, userPO);
        activityService.updateActivityJoinNum(request.getActivityId(), 1, new Date());
        this.increJoinedCount(request.getActivityId(), 1L);
    }

    public boolean joined(String activityId, String mobile) {
        Query query = new Query();
        query.addCriteria(Criteria.where("mobile").is(mobile).and("activityId").is(activityId));
        boolean exist = mongoTemplate.exists(query, UserParticipateActivityInfo.class);
        return exist;
    }

    @Async
    @Override
    public void removeSignUpByUserIdAndActivityId(String userId, String activityId) {
        Query query = new Query();
        query.addCriteria(Criteria.where("userId").is(userId));
        query.addCriteria(Criteria.where("activityId").is(activityId));
        this.mongoTemplate.remove(query, UserParticipateActivityInfo.class);
    }

    @Override
    public UserParticipateActivityInfo findJoinedUserByUserId(String userId) {
        Query query = new Query();
        query.addCriteria(Criteria.where("userId").is(userId));
        query.addCriteria(Criteria.where("joined").is(Boolean.TRUE));
        query.with(Sort.by(Sort.Direction.DESC, "id"));
        return this.mongoTemplate.findOne(query, UserParticipateActivityInfo.class);
    }

    @Override
    public void deleteUserSignUp(String id, String optMobile, String optUserId) {
        log.info("【操作员删除信息】id ->{} optUserId->{} optMobile->{}", id, optUserId, optMobile);
        if (StringUtils.isAllBlank(id, optUserId, optMobile)) {
            log.error("【操作员删除信息】参数为空 id ->{}| optUserId->{} | optMobile->{}", id, optUserId, optMobile);
            return;
        }
        String mobile = "";
        String userId = "";
        String activityId = "";
        UserParticipateActivityInfo userParticipateActivityInfo = this.mongoTemplate.findById(id,
                UserParticipateActivityInfo.class);
        if (Objects.nonNull(userParticipateActivityInfo)) {
            log.error("【操作员删除信息】 不存在 id ->{}| ", id);
            mobile = userParticipateActivityInfo.getMobile();
            userId = userParticipateActivityInfo.getUserId();
            activityId = userParticipateActivityInfo.getActivityId();
        } else {
            JinUserParticipate userParticipate = this.mongoTemplate.findById(id, JinUserParticipate.class);
            if (Objects.nonNull(userParticipate)) {
                mobile = userParticipate.getMobile();
                userId = userParticipate.getUserId();
                activityId = userParticipate.getActivityId();
            }
        }
        log.info("【操作员删除信息】 start id ->{} optUserId->{} optMobile->{}", id, optUserId, optMobile);
        if (StringUtils.isBlank(mobile)) {
            log.error("【操作员删除信息】 end 报名手机号为空 id ->{} optUserId->{} optMobile->{}", id, optUserId, optMobile);
            return;
        }
        if (!mobile.equals(optMobile)) {
            log.error("【操作员删除信息】 end 当前登录用户手机号与你报名信息手机号不一致 id ->{} optUserId->{} optMobile->{}", id, optUserId,
                    optMobile);
            throw new BusinessException("当前登录用户手机号与你报名信息手机号不一致");
        }
        Query query = new Query();
        query.addCriteria(Criteria.where("id").is(id));
        this.mongoTemplate.remove(query, UserParticipateActivityInfo.class);
        this.mongoTemplate.remove(query, JinUserParticipate.class);
        //删除答题信息

        query = new Query();
        query.addCriteria(Criteria.where("userId").is(userId));
        query.addCriteria(Criteria.where("activityGroupId").is(activityId));
        this.mongoTemplate.remove(query, UserCompetitionQaAnswer.class);
        query = new Query();
        query.addCriteria(Criteria.where("userId").is(userId));
        query.addCriteria(Criteria.where("activityId").is(activityId));
        this.mongoTemplate.remove(query, UserQaInfo.class);
        //删除答题信息
        this.mongoTemplate.remove(query, UserQuestionInfo.class);
        //删除证书信息
        this.mongoTemplate.remove(query, UserCa.class);

        //删除贡献值
        userActivityTaskRankingService.deleteByUserIdAndActivityId(userId, activityId);
        this.mongoTemplate.remove(query, UserActivityPointRanking.class);

        //排行榜
        //任务状态
        this.mongoTemplate.remove(query, UserActivityTaskInfo.class);
        this.mongoTemplate.remove(query, UserActivityPointDetail.class);


        //删除邀请记录
        this.mongoTemplate.remove(query, UserInviteCount.class);
        query = new Query();
        query.addCriteria(Criteria.where("invitedByUserId").is(userId));
        query.addCriteria(Criteria.where("activityId").is(activityId));
        this.mongoTemplate.remove(query, UserInviteRecord.class);


    }

    @Override
    public void initSignUpByActivityId(String activityId) {
        log.info("【start init sign up】");
        Query query = new Query();
        query.addCriteria(Criteria.where("activityId").is(activityId));
        List<UserParticipateActivityInfo> userList = this.mongoTemplate.find(query, UserParticipateActivityInfo.class);
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(userList)) {
            return;
        }
        ActivityQaInfo activityQaInfo = activityQaInfoService.findByActivityIdAndQaNumber(activityId, 1);
        userList.forEach(user -> {
            UserInfoExtend userInfoExtend = this.userInfoExtendService.findByUserId(user.getUserId());
            if (Objects.nonNull(userInfoExtend)) {
                if (StringUtils.isNotBlank(userInfoExtend.getMobile())) {
                    user.setMobile(userInfoExtend.getMobile());
                }
                if (StringUtils.isNotBlank(userInfoExtend.getUniversityName())) {
                    user.setUniversityName(userInfoExtend.getUniversityName());
                }
                if (StringUtils.isNotBlank(userInfoExtend.getUniversityId())) {
                    user.setUniversityId(userInfoExtend.getUniversityId());
                }
                if (StringUtils.isNotBlank(userInfoExtend.getName())) {
                    user.setName(userInfoExtend.getName());
                }
                if (StringUtils.isNotBlank(userInfoExtend.getNickName())) {
                    user.setNickName(userInfoExtend.getNickName());
                }
                UserQaInfo userQaInfo = userQaInfoService.findByUserIdAndQaInfoIdAndActivityId(user.getUserId(),
                        activityQaInfo.getId(), activityId);
                if (Objects.nonNull(user.getQaScore()) && Objects.nonNull(userQaInfo) && org.apache.commons.collections4.CollectionUtils.isNotEmpty(userQaInfo.getScoreSet())) {
                    user.setQaScore(userQaInfo.getScoreSet().stream().collect(Collectors.toList()).stream().max(Comparator.comparing(Double::doubleValue)).get());
                }
                this.mongoTemplate.save(user);
            }
        });


        log.info("【start init sign up】");
    }

    @Override
    public void initUserJoined() {
        Integer currentPageNo = 1;
        Integer pageSize = 10000;
        log.info("【初始化报名人数】start");
        while (true) {
            AtomicReference<Query> query = new AtomicReference<>(new Query());
            query.get().addCriteria(Criteria.where("joined").is(Boolean.FALSE));
            query.get().addCriteria(Criteria.where("universityId").exists(Boolean.TRUE));
            query.get().addCriteria(Criteria.where("universityName").exists(Boolean.TRUE));
            query.get().addCriteria(Criteria.where("name").exists(Boolean.TRUE));
            query.get().addCriteria(Criteria.where("mobile").exists(Boolean.TRUE));
            Pageable pageRequest = PageRequest.of(currentPageNo - 1, pageSize);
            List<UserParticipateActivityInfo> list = this.mongoTemplate.find(query.get().with(pageRequest),
                    UserParticipateActivityInfo.class);
            if (org.apache.commons.collections4.CollectionUtils.isEmpty(list)) {
                log.warn("【结束】当前第 {} 页结束", currentPageNo);
                break;
            }
            list.forEach(user -> {
                user.setJoined(Boolean.TRUE);
                user.setRemark("初始化报名用户");
                this.mongoTemplate.save(user);
            });
            currentPageNo++;
            log.warn("【初始化报名人数】当前第 {} 页", currentPageNo);
        }
        log.info("【初始化报名人数】end");


    }

    @Override
    public UserParticipateActivityInfo getJoinedLastByUserId(String userId) {
        Query query = new Query();
        query.addCriteria(Criteria.where("userId").is(userId).and("joined").is(Boolean.TRUE));
        query.with(Sort.by(Sort.Direction.DESC, "id"));
        query.limit(1);
        return this.mongoTemplate.findOne(query, UserParticipateActivityInfo.class);
    }

    @Override
    public void signUpInitCache(String activityId) {
        log.info("【更新初始化报名数据】活动ID ->{}", activityId);
        Query query = new Query();
        if (StringUtils.isBlank(activityId)) {
            Date now = new Date();
            query.addCriteria(Criteria.where("endTime").gte(now));
            List<ActivityInfo> activityInfoList = this.mongoTemplate.find(query, ActivityInfo.class);
            if (CollectionUtils.isEmpty(activityInfoList)) {
                log.info("【更新初始化报名数据】已结束");
                return;
            }
            activityInfoList.parallelStream().forEach(activityInfo -> {
                initSetSignUpCountByActivityId(activityInfo.getId());
            });
            log.info("【更新初始化报名数据】已结束");
            return;
        }
        initSetSignUpCountByActivityId(activityId);
        log.info("【更新初始化报名数据】已结束");
    }

    @Override
    public UserParticipateActivityInfo findReceiveCaUserByUserIdActivityId(String userId, String activityId) {
        Query query = new Query();
        query.addCriteria(Criteria.where("userId").is(userId).and("activityId").is(activityId));
        return masterMongoTemplate.findOne(query, UserParticipateActivityInfo.class);
    }

    @Async
    @Override
    public void updateSignInDay(String userId, String activityId) {
        //更新记录打卡天数
        Query query = new Query();
        query.addCriteria(Criteria.where("userId").is(userId).and("activityId").is(activityId));
        Update update = new Update();
        update.inc("userSignInDay", 1);
        this.mongoTemplate.updateFirst(query, update, UserParticipateActivityInfo.class);
    }

    @Override
    public Boolean updateInvitedNum(Date date) {
        log.info(":>>> 开始更新活动报名人数:{}", date);
        Query query = new Query();
        query.addCriteria(Criteria.where("startTime").lte(date).and("endTime").gte(date));
        List<ActivityInfo> activityInfos = mongoTemplate.find(query, ActivityInfo.class);
        for (ActivityInfo activityInfo : activityInfos) {
            userInviteService.updateInvitedNum(activityInfo.getId());
        }
        return Boolean.TRUE;
    }

    @Override
    public void deleteByUserIdAndActivityId(String userId, String activityId) {
        log.info("deleteByUserIdAndActivityId userId:{},activityId:{}", userId, activityId);
        Query query = new Query();
        query.addCriteria(Criteria.where("userId").is(userId));
        query.addCriteria(Criteria.where("activityId").is(activityId));
        DeleteResult deleteResult = mongoTemplate.remove(query, UserParticipateActivityInfo.class);
        log.info("deleteByUserIdAndActivityId deleteResult:{}", JSONObject.toJSONString(deleteResult));
    }

    private void initSetSignUpCountByActivityId(String activityId) {
        if (StringUtils.isBlank(activityId)) {
            return;
        }
        Long signUpCount = getSignUpCountByActivityId(activityId);
        log.info(":>>> activityId->{} | 报名人数:{}", activityId, signUpCount);
        initSetCacheJoinedCount(activityId, signUpCount);
    }

    public void initSetCacheJoinedCount(String activityId, Long incr) {
        log.info(":>>> 开始初始化活动报名人数:{},{}", activityId, incr);
        try {
            String key = getJoinedCountKey(activityId);
            redisTemplate.delete(key);
            this.increJoinedCount(activityId, incr);
        } catch (Exception e) {
            log.error(":>>> 初始化活动报名人数,错误:{}", e);
            return;
        }

    }

    private Long getSignUpCountByActivityId(String activityId) {
        Query query = new Query();
        query.addCriteria(Criteria.where("activityId").is(activityId).and("joined").is(Boolean.TRUE));
        return this.mongoTemplate.count(query, UserParticipateActivityInfo.class);
    }

    protected String getJoinedCountKey(String prekey) {
        String key = String.format(ACTIVITY_COUNT_USERS_PEFIX, prekey);
        log.info(":>>> 报名人数:{},key:{}", prekey, key);
        return key;
    }
}
